import wx
from socket import *
# 创建多线程
import threading
# 管理多线程
from concurrent.futures import ThreadPoolExecutor

class Server(wx.Frame):
    def __init__(self):
        # 实例属性
        self.isOn = False  # 服务器启状态
        self.server_socket = socket()  # 创建socket对象
        self.server_socket.bind(("0.0.0.0", 8999))  # 绑定ip和端口号
        self.server_socket.listen(5)  # 监听
        # 保存所有的客户端
        self.client_thread_dict = {}
        # 创建线程池，最大10
        self.thread_pool = ThreadPoolExecutor(max_workers=10)

        # 界面布局:
        super().__init__(None, title="多人聊天室服务器", pos=(0, 50), size=(450, 670))
        # 创建面板
        self.pl = wx.Panel(self)
        # 创建按钮：
        # 启动服务器
        self.start_server_btn = wx.Button(self.pl, label="启动服务器", pos=(10, 10), size=(200, 40))
        # 保存聊天记录
        self.save_history_btn = wx.Button(self.pl, label="保存聊天记录", pos=(220, 10), size=(200, 40))
        # 创建聊天内容文本框
        self.read_text = wx.TextCtrl(self.pl, size=(420, 400), pos=(10, 60), style=wx.TE_READONLY | wx.TE_MULTILINE)

        # 给按钮绑定事件
        self.Bind(wx.EVT_BUTTON, self.onStart, self.start_server_btn)
        self.Bind(wx.EVT_BUTTON, self.onSave, self.save_history_btn)

    # 启动服务器
    def onStart(self, event):
        print("onStart")
        if self.isOn == False:
            self.isOn = True
            # 创建线程
            main_thread = threading.Thread(target=self.main_thread_fun)
            # 设置为守护线程
            main_thread.daemon = True
            # 启动线程
            main_thread.start()


    def main_thread_fun(self):
        while self.isOn:
            try:
                client_socket, client_addr = self.server_socket.accept()
                client_name = client_socket.recv(1024).decode("utf8")
                print(f"客户端 {client_name} 连接")
                # 要保存所有的客户端，并且用线程处理，以便群发消息：
                # 创建线程
                client_thread = ClientTread(client_socket, client_name, self)
                # 启动线程的接收循环
                client_thread.isOn = True
                # 保存客户端
                self.client_thread_dict[client_name] = client_thread
                # 启动线程
                client_thread.start()
                # 群发欢迎消息
                self.onGroupMessaging("【服务器通知】：欢迎 %s 进入聊天室" %client_name)
            except Exception as e:
                print(f"接收连接出错：{e}")
                if not self.isOn:
                    break


    def onGroupMessaging(self, text):
        # 给自己发送提示
        self.read_text.AppendText(text + "\n")
        # 给客服端发送消息
        to_remove = []
        for client_name, client in self.client_thread_dict.items():
            if client.isOn:
                try:
                    client.client_socket.send(text.encode("utf8"))
                except Exception as e:
                    print(f"发送给 {client_name} 失败：{e}")
                    client.isOn = False
                    to_remove.append(client_name)
        # 移除断开的客户端
        for name in to_remove:
            del self.client_thread_dict[name]


    # 保存聊天记录
    def onSave(self, event):
        print("onSave")
        # 保存聊天记录
        record = self.read_text.GetValue()
        with open("chat_recode.log", "a+", encoding="utf-8") as file:
            file.write(record + "\n")


class ClientTread(threading.Thread):
    def __init__(self, client_socket, client_name, server):
        super().__init__()
        self.client_socket = client_socket
        self.client_name = client_name
        self.server = server
        self.isOn = False


    def run(self):
        while self.isOn:
            try:
                text = self.client_socket.recv(1024).decode("utf8")
                if text == "断开连接":
                    self.isOn = False
                    # 通知服务器群发“离开”消息
                    self.server.onGroupMessaging("【服务器消息】：%s 离开了聊天室" %self.client_name)
                else:
                    # 转发用户消息
                    self.server.onGroupMessaging("【%s 消息】：%s" %(self.client_name, text))
            except Exception as e:
                print(f"客户端线程出现问题：{e}")
                self.isOn = False
        # 关闭连接并从服务器字典移除
        try:
            self.client_socket.close()
        except Exception as e:
            print(f"连接关闭失败：{e}")
        if self.client_name in self.server.client_thread_dict:
            del self.server.client_thread_dict[self.client_name]


if __name__ == "__main__":
    # 创建应用程序对象
    app = wx.App()
    # 创建服务器窗口
    server = Server()
    # 显示窗口
    server.Show()
    # 一直循环显示
    app.MainLoop()